if 'google.colab' in str(get_ipython()):
import os, sys
os.chdir('/content')
print('Nastavení prostředí Google Colab.')
! git clone "https://github.com/jarbes/snemovna.git" --branch master
sys.path.insert(0,'/content/snemovna')
os.chdir('/content/snemovna')
! pip install -r requirements.txt
from datetime import datetime, timedelta
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import numpy as np
from snemovna.Hlasovani import Hlasovani, Omluvy, HlasovaniPoslanci, ZpochybneniHlasovani, ZmatecneHlasovani
from snemovna.PoslanciOsoby import Poslanci, Organy, ZarazeniOsoby
from snemovna.Stenotexty import Stenotexty
from snemovna.Schuze import Schuze
from snemovna.utility import groupby_bar, sort_column_by_predefined_order
from nastav_jupyter_notebook import nastav_pandas
# nastavení výpisu, například zobrazení delších textů v sloupcích tabulek
nastav_pandas()
clean_layout = dict(
plot_bgcolor="#FFFFFF",
)
y_spikes = dict(
yaxis=dict(
linecolor="#BCCCDC",
showspikes=True,
spikethickness=1,
spikedash="dot",
spikecolor="#999999",
spikemode="across",
)
)
x_spikes = dict(
xaxis=dict(
linecolor="#BCCCDC",
showspikes=True,
spikethickness=1,
spikedash="dot",
spikecolor="#999999",
spikemode="across",
)
)
clean_layout_with_x_spikes = {**clean_layout, **x_spikes}
clean_layout_with_y_spikes = {**clean_layout, **y_spikes}
clean_layout_with_xy_spikes = {**clean_layout, **x_spikes, **y_spikes}
categorical_scale1 = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']
# formát výpisu data
format_den = "%d. %m. %Y"
stahni=True
# načti informace o poslancích (jméno, příjemní, za koho kandidovali, etc.)
p = Poslanci(stahni=stahni)
print(p.columns)
p.head(2)
zo = ZarazeniOsoby(stahni=stahni)
print(zo.columns)
zo.head(2)
# načti informace o schůzích PS (kdy začaly, v jakém jsou stavu, etc.)
sch = Schuze(stahni=stahni)
print(sch.columns)
sch.head(2)
# načti informace o jednotlivých hlasováních
h = Hlasovani(stahni=stahni)
print(h.columns)
h.head(2)
zph = ZpochybneniHlasovani(stahni=stahni)
print(zph.columns)
zph.head()
zmh = ZmatecneHlasovani(stahni=stahni)
print(zmh.columns)
zmh.head()
# načti indiviuální hlasování poslanců
hp = HlasovaniPoslanci(stahni=stahni)
print(hp.columns)
hp.head(2)
assert hp.id_osoba.nunique() <= p.id_osoba.nunique() or print("Nekonzistence v tabulkách 'HlasovaniPoslanci' a 'Poslanci': hlasujících poslanců je méně než těch, kteří hlasovali!")
# načti omluvy poslanců ze schůze PS
om = Omluvy(stahni=stahni)
print(om.columns)
om.head(2)
assert om[om.je_poslanec].id_osoba.nunique() <= p.id_osoba.nunique() or print("Nekonzistence v tabulkách 'Omluvy' a 'Poslanci': osob je méně než osob, které se omlouvali!")
# Stenotexty zde nebudeme potřebovat
#st = Stenotexty(stahni=stahni)
#print(st.columns)
#st.head()
volebni_obdobi = h.volebni_obdobi
snemovna = h.snemovna
pocet_poslancu_dle_klubu = p[p.do_parlament.isna()].groupby('zkratka_klub').size().sort_values(ascending=False)
fig = go.Figure(go.Bar(
x=pocet_poslancu_dle_klubu.index,
y=pocet_poslancu_dle_klubu.values,
marker=dict(
color=list(range(len(pocet_poslancu_dle_klubu.index))),
colorscale=categorical_scale1
),
hovertemplate="<b>%{x}</b><br>Počet poslanců: %{y}<extra></extra>"
))
layout = go.Layout(
title="Aktuální počet poslanců dle poslaneckého klubu (strany)",
xaxis=dict(title="Strana", type='category'),
yaxis=dict(title="Počet poslanců")
)
fig.update_layout(clean_layout_with_y_spikes)
fig.update_layout(layout)
fig.show()
fig = go.Figure()
schuze = sch[sch.pozvanka.isna()]
for _, s in schuze.iterrows():
id_schuze = s.schuze
dny_hlasovani = h[h.schuze == id_schuze].datum.dt.date.unique()
od = s.od_schuze
do = sch.tzn.localize(datetime.today()) if pd.isna(s.do_schuze) else s.do_schuze
dny = [od.date()] + [d for d in dny_hlasovani if (d >= od.date()) and ((d <= do.date()) | pd.isna(do))] + [do.date()]
dny = list(set(dny))
datum_hovertemplate = f"od {od.strftime(format_den)}" if pd.isna(s.do_schuze) \
else f"{od.strftime(format_den)} - {s.do_schuze.strftime(format_den)}"
tm_line_hovertemplate= '' if pd.isna(s.tm_line) else s.tm_line
fig.add_trace(go.Scatter(
x=dny,
y=[s.schuze]*len(dny),
text=s.schuze,
hovertemplate=f"Schůze {s.schuze}<br>" \
"Datum: %{x}<br>"\
f"Trvání schůze: {datum_hovertemplate}<br>"\
f"Typ schůze: {s.typ}<br>" \
f"{tm_line_hovertemplate}<extra></extra>",
mode="lines+markers",
line = dict(shape='linear', width=15),
marker = dict(symbol='star-diamond', size=10),
))
fig.update_traces(marker=dict(line=dict(width=1, color='black')))
fig.update_layout(clean_layout_with_xy_spikes)
layout = go.Layout(
title="Schůze poslanecké sněmovny v čase",
xaxis=dict(title="Čas"),
yaxis=dict(title="Schůze", type='category'),
height=600,
showlegend=False
)
fig.update_layout(layout)
fig.show()
import plotly.express as px
h["pocet_dni_na_schuzi"] = h.groupby(["schuze"]).datum.transform('nunique')
h['den'] = h.datum.dt.date
h["den_schuze"] = h.groupby(["schuze", h.datum.dt.date]).ngroup()
h["den_schuze_min"] = h.groupby(["schuze"]).den_schuze.transform(min)
h["den_schuze_rank"] = (h["den_schuze"] - h["den_schuze_min"] + 1)
x1 = h.groupby(["schuze", 'den', "den_schuze_rank"]).size()
z1 = x1.reset_index(name="pocet_hlasovani")
print(f"Na schůzích {sorted(set(range(z1.schuze.max() + 1)) - set(z1.schuze.unique()) - set([0]))} se nehlasovalo.")
fig = px.bar(z1, x="schuze", y="pocet_hlasovani",
color="den_schuze_rank",
hover_data=['schuze', 'den_schuze_rank', 'pocet_hlasovani', 'den'],
labels={'schuze':'Schůze', 'den': 'Datum', 'den_schuze_rank': 'Pořadí dne schůze', 'pocet_hlasovani': 'Počet hlasování'},
title="Počet hlasování dle dne schůze")
layout = go.Layout(
title="Počet hlasování dle schůze",
plot_bgcolor="#FFFFFF",
#hovermode="x",
#hoverdistance=100, # Distance to show hover label of data point
#spikedistance=1000, # Distance to show spike
xaxis=dict(
title="Schůze sněmovny",
linecolor="#BCCCDC",
#type='category'
),
yaxis=dict(
title="Počet hlasování",
linecolor="#BCCCDC",
showspikes=True,
spikethickness=1,
spikedash="dot",
spikecolor="#999999",
spikemode="across",
)
)
fig.update_layout(layout)
def pocet_hlasovani_dle_data(df, resample_to, resample_str, resample_label):
frame = df.set_index('datum').resample(resample_to).size()
frame = frame.mask(frame == 0, None).dropna()
max_idx = frame.sort_values().index[-1]
min_idx = frame.sort_values().index[0]
print(f"Nejvíce hlasování ({frame.loc[max_idx]}) se uskutečnilo {max_idx.strftime(resample_str)}.")
print(f"Nejméně hlasování ({frame.loc[min_idx]}) se uskutečnilo {min_idx.strftime(resample_str)}.")
fig = go.Figure()
fig.add_trace(go.Bar(
x=frame.index,
y=frame.values,
marker=dict(
color=frame.values,
colorscale='Bluered'
),
hovertemplate="%{x}<br>počet hlasování: %{y}<extra></extra>"
))
fig.update_layout(
title=f"Počet hlasování dle data ({resample_label})",
xaxis_title=f"datum ({resample_label})",
yaxis_title="počet hlasování",
width=1200,
height=500
)
dt_all = pd.date_range(start=frame.index[0],end=frame.index[-1])
dt_obs = [d.strftime(resample_str) for d in frame.index]
dt_breaks = [d for d in dt_all.strftime(resample_str).tolist() if not d in dt_obs]
# nezobrazuj data bez hlasování
#dt_all = pd.date_range(start=df.index[0], end=df.index[-1])
#dt_obs = [d.strftime(resample_str) for d in df.index]
#dt_breaks = [d for d in dt_all.strftime(resample_str).tolist() if not d in dt_obs]
fig.update_xaxes(
rangebreaks=[dict(values=dt_breaks)]
)
fig.show()
pocet_hlasovani_dle_data(h, "D", "%Y-%m-%d", "den")
# Za hlasovací dny označujeme takové, během nichž se sešla Sněmovna a o něčem se hlasovalo.
# TODO: Existují dny, kdy se konala schůze PS, ale o ničem se nehlasovalo? Jak je najdeme?
minimalni_pocet_hlasovacich_dni = 30
hlasovaci_dny = pd.to_datetime(h.datum.dt.date.unique()).tz_localize(h.tzn)
pocet_hlasovacich_dni = len(hlasovaci_dny)
def fce_pocet_omluvenych_dni(id_poslanec):
return om[(om.je_poslanec) & (om.id_poslanec == id_poslanec)].den.dt.date.nunique()
p['pocet_omluvenych_dni'] = p.id_poslanec.apply(fce_pocet_omluvenych_dni).astype('Int64')
assert p[p['pocet_omluvenych_dni'] > pocet_hlasovacich_dni].index.size == 0, \
f"Chyba ve výpočtu. Počet omluvenych dní poslance musí být menší než {pocet_hlasovacich_dni}."
p['pocet_hlasovacich_dni'] = p.apply(lambda row:
len(hlasovaci_dny[(hlasovaci_dny >= row['od_parlament'])
& ((hlasovaci_dny <= row['do_parlament']) | pd.isna(row['do_parlament']))])
, axis=1).astype('Int64')
assert p[p['pocet_hlasovacich_dni'] > pocet_hlasovacich_dni].index.size == 0,\
f"Chyba ve výpočtu. Počet hlasovacích dní poslance musí být menší než {pocet_hlasovacich_dni}."
p['pomer_omluvenych_dni'] = p['pocet_omluvenych_dni'] / p['pocet_hlasovacich_dni']
assert p[
(p.pocet_hlasovacich_dni > minimalni_pocet_hlasovacich_dni)
& ((p['pomer_omluvenych_dni'] > 1) | (p['pomer_omluvenych_dni'] < 0))].index.size == 0,\
f"Chyba ve výpočtu. Poměr omluvených dní poslance musí být v intervalu [0, 1]]."
if pd.isna(h.snemovna.do_organ):
print(f"Sněmovna {volebni_obdobi} se začala scházet {snemovna.od_organ.strftime(format_den)}.")
if len(h) > 0:
print(f"Naposledy se hlasovalo {h.datum.sort_values().dt.strftime(format_den).iloc[-1]}.")
else:
print(f"Sněmovna {volebni_obdobi} se začala scházet {snemovna.od_organ.strftime(format_den)} a skončila {snemovna.do_organ.strftime(format_den)}.")
print(f"Hlasovalo se během {pocet_hlasovacich_dni} dní.")
print(f"Průměrný poměr omluvených dnů: {p[p.pocet_hlasovacich_dni >= minimalni_pocet_hlasovacich_dni].pomer_omluvenych_dni.mean():.2f}.")
print(f"Medián poměr omluvených dnů: {p[p.pocet_hlasovacich_dni >= minimalni_pocet_hlasovacich_dni].pomer_omluvenych_dni.median():.2f}.")
fig = go.Figure(go.Box(y=p[p.pocet_hlasovacich_dni >= minimalni_pocet_hlasovacich_dni].pomer_omluvenych_dni))
fig.show()
fig = go.Figure()
for zkratka_klub in p.zkratka_klub.unique():
data = p[(p.zkratka_klub == zkratka_klub) & (p.pocet_hlasovacich_dni >= minimalni_pocet_hlasovacich_dni)]
fig.add_trace(go.Box(y=data.pomer_omluvenych_dni, name=zkratka_klub))
layout = go.Layout(
title="Poměr počtu omluvených dní ku počtu hlasovacích dní dle poslaneckého klubu (strany)",
xaxis=dict(title="Strany", type='category'),
yaxis=dict(title="Poměr omluvených dní")
)
fig.update_layout(clean_layout_with_x_spikes)
fig.update_layout(layout)
fig.show()
data = pd.DataFrame([])
for zkratka_klub in p.zkratka_klub.unique():
v = p[(p.zkratka_klub == zkratka_klub) & (p.pocet_hlasovacich_dni >= minimalni_pocet_hlasovacich_dni)].pocet_omluvenych_dni.sum()
data.loc[zkratka_klub, 'pocet_omluvenych_dni'] = v
fig = go.Figure()
fig.add_trace(go.Bar(x=data.index, y=data.pocet_omluvenych_dni))
layout = go.Layout(
title="Počet omluvených dní dle poslaneckého klubu (strany)",
xaxis=dict(title="Strany", type='category'),
yaxis=dict(title="Poměr omluvených dní")
)
fig.update_layout(clean_layout_with_x_spikes)
fig.update_layout(layout)
fig.show()
print(f"Průměrný počet omluvených dnů: {p[(p.pocet_hlasovacich_dni >= minimalni_pocet_hlasovacich_dni)].pocet_omluvenych_dni.mean():.1f}.")
print(f"Medián počtu omluvených dnů: {p[(p.pocet_hlasovacich_dni >= minimalni_pocet_hlasovacich_dni)].pocet_omluvenych_dni.median():.1f}.")
go.Figure(go.Histogram(x=p[(p.pocet_hlasovacich_dni >= minimalni_pocet_hlasovacich_dni)].pomer_omluvenych_dni))
go.Figure(go.Histogram(x=p[(p.pocet_hlasovacich_dni >= minimalni_pocet_hlasovacich_dni)].pocet_omluvenych_dni))
cnt = 10
print(f"Poslanci s nejmenším počtem dnů, během nichž se omluvali z hlasování PS.")
fields = ['id_poslanec', 'jmeno', 'prijmeni', 'pomer_omluvenych_dni', 'pocet_omluvenych_dni', 'pocet_hlasovacich_dni', 'zkratka_klub']
p[(p.pocet_hlasovacich_dni >= minimalni_pocet_hlasovacich_dni)].sort_values(by="pocet_omluvenych_dni")[fields].head(cnt)
cnt = 10
print(f"Poslanci s největším počtem dnů, během nichž se omluvali z hlasování PS.")
fields = ['id_poslanec', 'jmeno', 'prijmeni', 'pomer_omluvenych_dni', 'pocet_omluvenych_dni', 'pocet_hlasovacich_dni', 'zkratka_klub']
p[(p.pocet_hlasovacich_dni >= minimalni_pocet_hlasovacich_dni)].sort_values(by="pocet_omluvenych_dni")[::-1][fields].head(cnt)
cnt = 10
print(f"Poslanci s nejmenším poměrem dnů, během nichž se omluvali z hlasování PS.")
fields = ['id_poslanec', 'jmeno', 'prijmeni', 'pomer_omluvenych_dni', 'pocet_omluvenych_dni', 'pocet_hlasovacich_dni', 'zkratka_klub']
p[(p.pocet_hlasovacich_dni >= minimalni_pocet_hlasovacich_dni)].sort_values(by="pomer_omluvenych_dni")[fields].head(cnt)
cnt = 10
print(f"Poslanci s největším poměrem dnů, během nichž se omluvali z hlasování PS.")
fields = ['id_poslanec', 'jmeno', 'prijmeni', 'pomer_omluvenych_dni', 'pocet_omluvenych_dni', 'pocet_hlasovacich_dni', 'zkratka_klub']
p[(p.pocet_hlasovacich_dni >= minimalni_pocet_hlasovacich_dni)].sort_values(by="pomer_omluvenych_dni")[::-1][fields].head(cnt)
Následující analýza slouží k tomu, abychom lépe pochopili, jakým způsobem se hlasujev PS ČR. Proč je tomu třeba rozumět? Některá hlasování (například hlasování o zpochybnění hlasování) mají technický charakter. V některých analýzách je může být vhodné vynechat.
Přibližná pravidla pro určení platnosti hlasování:
hl_pocet = h.id_hlasovani.nunique()
zpochybneni = zph[zph.je_platne == True]
zm_hl = h[h.id_hlasovani.isin(zmh.id_hlasovani)]
zm_hl_pocet = zm_hl.id_hlasovani.nunique()
zp_hl = h[h.id_hlasovani.isin(zpochybneni.id_hlasovani)]
zp_hl_pocet = zp_hl.id_hlasovani.nunique()
pouze_v_tabulce_zpochybneni_pocet = len(set(zph.id_hlasovani) - set(h.id_hlasovani))
pouze_v_tabulce_zmatecne_pocet = len(set(zmh.id_hlasovani) - set(h.id_hlasovani))
print(f"Základní vlastnosti tabulky Hlasovani (pro sněmovnu {h.volebni_obdobi}):")
print(f"- {hl_pocet} hlasování, z toho")
print(f"- {zm_hl_pocet} ({100 * (zm_hl_pocet / hl_pocet):.2f}%) hlasování bylo označeno za zmatečné,")
print(f"- {zp_hl_pocet} ({100 * (zp_hl_pocet / hl_pocet):.2f}%) hlasování bylo zpochybněno.")
df = zpochybneni[zpochybneni.mode__KAT == 'pouze pro stenozáznam']
v1 = h[h.id_hlasovani.isin(df.id_hlasovani)].id_hlasovani.nunique()
print(f"\t- {v1} hlasování z tabulky Hlasování bylo zpochybněno, ale zpochybnění bylo uvedeno jen pro stenozáznam.")
df = zpochybneni[zpochybneni.mode__KAT == 'žádost o opakování']
v1 = h[h.id_hlasovani.isin(df.id_hlasovani)].id_hlasovani.nunique()
print(f"\t- {v1} hlasování z tabulky Hlasování bylo zpochybněno s žádostí o opakování hlasování.")
df = zpochybneni[(zpochybneni.mode__KAT == 'žádost o opakování') & ~(zpochybneni.id_h2.isna()| zpochybneni.id_h3.isna())]
v1 = h[h.id_hlasovani.isin(df.id_hlasovani)].id_hlasovani.nunique()
print(f"\t\t- {v1} hlasování z tabulky Hlasování bylo zpochybněno s žádostí o opakování hlasování, o zpochybnění se hlasovalo a původní hlasování se následně opakovalo.")
df = zpochybneni[(zpochybneni.mode__KAT == 'žádost o opakování') & ~zpochybneni.id_h2.isna() & zpochybneni.id_h3.isna()]
v1 = h[h.id_hlasovani.isin(df.id_hlasovani)].id_hlasovani.nunique()
print(f"\t\t- {v1} hlasování z tabulky Hlasování bylo zpochybněno s žádostí o opakování hlasování, o zpochybnění se hlasovalo, ale původní hlasování se neopakovalo.")
print()
print(f"Dalších {pouze_v_tabulce_zpochybneni_pocet} hlasování je uvedeno pouze v tabulce ZpochybneniHlasovani. ")
print(f"Dalších {pouze_v_tabulce_zmatecne_pocet} hlasování je uvedeno pouze v tabulce ZmatecneHlasovani.")
print()
print(f"Celkově tedy proběhlo ve sněmovně až {hl_pocet + pouze_v_tabulce_zpochybneni_pocet + pouze_v_tabulce_zmatecne_pocet} hlasování.")
print()
print("Poznámka: Tabulka ZmatecneHlasovani nemá explicitně určenou vazbu na danou sněmovnu. Její propojení s tabulkou Hlasování bylo provedeno následující heuristikou: "
"Pro danou sněmovnu se určí minimální a maximální identifikátor hlasování. Pro dané zmatečné hlasování pak musí platit, že min(id(hlasování)) <= id(zmatečného hlasování) <= max(id(hlasování)).")
def flatten(ary):
return [x for l in ary for x in l]
def fce_mezi_hlasovanim_a_hlasovanim_o_zpochybneni_hlasovani_ids(row):
if pd.isna(row['id_h2']):
return []
else:
return list(range(row['id_hlasovani']+1, row['id_h2']))
# Hlasování o zpochybnění hlasování je možné také zkazit nebo zpochybnit.
# Mezi prvním hlasováním o zpochybnění a opakovaným hlasováním může proběhnout několik dalších zpochybněných nebo neplatných hlasování.
def fce_mezi_hlasovanim_o_zpochybneni_a_opakovanym_hlasovanim_ids(row):
if pd.isna(row['id_h2']):
return []
elif pd.isna(row['id_h3']):
return []
else:
return list(range(row['id_h2']+1, row['id_h3']))
mezi_hlasovanim_a_hlasovanim_o_zpochybneni_hlasovani_ids = \
flatten(zpochybneni[zpochybneni.mode__KAT == 'žádost o opakování'].apply(fce_mezi_hlasovanim_a_hlasovanim_o_zpochybneni_hlasovani_ids, axis=1))
mezi_hlasovanim_o_zpochybneni_a_opakovanym_hlasovani_ids = \
flatten(zpochybneni[zpochybneni.mode__KAT == 'žádost o opakování'].apply(fce_mezi_hlasovanim_o_zpochybneni_a_opakovanym_hlasovanim_ids, axis=1))
hlasovani_o_zpochybneni_ids = h[h.id_hlasovani.isin(zpochybneni.id_h2.unique())]
hlasovani_bez_zmatecnych_a_zpochybnenych = h[~h.id_hlasovani.isin(zmh.id_hlasovani)
& ~h.id_hlasovani.isin(zph[zph.mode__KAT == 'žádost o opakování'].id_hlasovani)
& ~h.id_hlasovani.isin(mezi_hlasovanim_o_zpochybneni_a_opakovanym_hlasovani_ids)
& ~h.id_hlasovani.isin(hlasovani_o_zpochybneni_ids)
]
h_platne = hlasovani_bez_zmatecnych_a_zpochybnenych.copy()
h_platne["mira_jednomyslnosti"] = (h_platne.pro - h_platne.proti).abs() / (h_platne.pro + h_platne.proti)
h_platne["mira_jednomyslnosti"].describe()
fig = go.Figure(go.Histogram(
x=h_platne.mira_jednomyslnosti,
hovertemplate="míra jednomyslnosti: %{x}<br>počet hlasování: %{y}<extra></extra>"))
fig.update_layout(width=700, height=400, xaxis=dict(title="míra jednomyslnosti"), yaxis=dict(title="počet hlasování"))
fig.show()
# denní míra jednomyslnosti
precision = 3
def A_razeno_dle_B(x, A, B):
df = x.groupby(A)[B].mean().sort_values(ascending=True)
return("<br>".join(map(str, df.index.astype(str) + ': ' + df.values.round(precision).astype(str))))
days = 7
interval = f"{days}D"
df = pd.DataFrame()
df['mira_jednomyslnosti_za_den_mean'] = h_platne.groupby(h_platne.datum.dt.date).mira_jednomyslnosti.mean()
df['nazev_dlouhy_za_den'] = h_platne.groupby(h_platne.datum.dt.date)[['nazev_dlouhy', 'mira_jednomyslnosti']].apply(
lambda x: A_razeno_dle_B(x, "nazev_dlouhy", "mira_jednomyslnosti")
)
df.index = pd.to_datetime(df.index)
fig = go.Figure()
fig.add_trace(go.Scatter(
x=df.index,
y=df.mira_jednomyslnosti_za_den_mean,
text=df.nazev_dlouhy_za_den,
name="míra jednomyslnosti za den",
mode="markers",
marker=dict(
size=5,
color=df.mira_jednomyslnosti_za_den_mean,
colorscale='RdYlGn', # one of plotly colorscales
showscale=True
),
hovertemplate =
'<b>%{x}</b>'+
'<br><br><b>Průměrná míra jednomyslnosti</b>: <i>%{y:.3f}</i>'+
'<br><br><b>Hlasování dle míry jednomyslnosti (vzestupně):</b><br>%{text}<extra></extra>',
hoverlabel=dict(
bgcolor='white',
font=dict(color='black')
)
))
fig.update_layout(title="Denní míra jednomyslnosti", xaxis=dict(title="datum [jednotlivé dny]"), yaxis=dict(title="míra jednomyslnosti"))
fig.show()
print(f"Jednomyslně schválená hlasování (vysoká míra jednomyslnosti): {h_platne[h_platne.mira_jednomyslnosti == 1].index.size}")
jednomyslna_temata = h_platne[h_platne.mira_jednomyslnosti == 1].groupby('nazev_dlouhy').size().sort_values(ascending=False)
print(jednomyslna_temata.head(20))
print(f"Hlasování s nízkou mírou jednomyslnosti (zcela vyrovnané pro a proti)): {h_platne[h_platne.mira_jednomyslnosti == 0].index.size}")
nejednomyslna_temata = h_platne[h_platne.mira_jednomyslnosti == 0].groupby('nazev_dlouhy').size().sort_values(ascending=False)
print(nejednomyslna_temata.head(20))
# Témata hlasování s nejvyšší mírou jednomyslnosti a jejich počty
cnt = 5
x = pd.DataFrame()
x['celkovy_pocet_hlasovani_dle_tematu'] = h_platne.groupby('nazev_dlouhy').size()
x['prumerna_mira_jednomyslnosti_dle_tematu'] = h_platne.groupby('nazev_dlouhy')['mira_jednomyslnosti'].mean()
x.sort_values(by='prumerna_mira_jednomyslnosti_dle_tematu', ascending=False).head(cnt)
# Témata hlasování s nízkou mírou jednomyslnosti a jejich počty
cnt = 5
x = pd.DataFrame()
x['celkovy_pocet_hlasovani_dle_tematu'] = h_platne.groupby('nazev_dlouhy').size()
x['prumerna_mira_jednomyslnosti_dle_tematu'] = h_platne.groupby('nazev_dlouhy')['mira_jednomyslnosti'].mean()
x.sort_values(by='prumerna_mira_jednomyslnosti_dle_tematu', ascending=False).tail(cnt)
%%time
df = hp[hp.id_hlasovani.isin(h_platne.id_hlasovani)]
data = df[['id_osoba', 'id_hlasovani', 'vysledek', 'zkratka_klub']]\
.set_index('id_osoba')\
.sort_values(by=['zkratka_klub'])[['id_hlasovani', 'vysledek']]\
.groupby('id_osoba', sort=False)\
.apply(lambda g: list(map(tuple, g.values))).to_dict()
data = {osoba: [str(hl_idx) + '_' + vysledek for hl_idx, vysledek in data[osoba]] for osoba in data.keys()}
%%time
def jaccard_similarity(list1, list2):
intersection = len(list(set(list1).intersection(list2)))
union = (len(list1) + len(list2)) - intersection
return float(intersection) / union
m = {}
for osoba1, v1 in data.items():
if osoba1 not in m:
m[osoba1] = {}
for osoba2, v2 in data.items():
m[osoba1][osoba2] = jaccard_similarity(v1, v2)
korelace_df = pd.DataFrame(m)
osoby = {id_osoba: hp[hp.id_osoba == id_osoba][['jmeno', 'prijmeni', 'zkratka_kandidatka','nazev_kraj_cz', 'zkratka_klub']].iloc[0] for id_osoba in korelace_df}
jmeno_prijmeni = [f"{osoby[id_osoba]['jmeno']} {osoby[id_osoba]['prijmeni']}" for id_osoba in korelace_df.index]
zkratka_klub = [osoby[id_osoba]['zkratka_klub'] for id_osoba in korelace_df.index]
label = [f"{j} ({zk})" for j, zk in zip(jmeno_prijmeni, zkratka_klub)]
import plotly.graph_objects as go
fig = go.Figure(data=go.Heatmap(
z=korelace_df,
x=label,
y=label,
colorscale='Viridis',
hovertemplate="%{x}<br>%{y}<br>Podobnost hlasování: %{z}<extra></extra>"
))
fig.update_layout(title='Podobnost hlasování poslanců', width=800, height=800)
fig.update_xaxes(type='category', tickangle=45)
fig.update_yaxes(type='category', autorange='reversed')
fig.show()
print(f"Poslední běh notebooku: {datetime.now().strftime('%d.%m.%Y %H:%M:%S')}.")